class WebrtcConnection {
  protected peerconnection: RTCPeerConnection | null;

  constructor() {
    this.peerconnection = null;
  }

  // 创建和初始化 peerconnection
  async create(
    onCandidate: (candidate: RTCIceCandidate) => void,
    onTrack: (event: RTCTrackEvent) => void
  ) {
    // 创建 RTC 连接
    this.peerconnection = new RTCPeerConnection({
      bundlePolicy: "max-bundle",
      rtcpMuxPolicy: "require",
      // iceTransportPolicy: 'relay',// 强制服务器转发ICE候选
      iceServers: [
        {
          urls: "stun:stun.l.google.com:19302", // Google的STUN服务器
        },
        // 可以添加更多 STUN 和 TURN 服务器
      ],
    });

    // ICE 候选事件：当媒体协商完成，TURN 服务器返回 ICE 候选时触发
    this.peerconnection.onicecandidate = (event) => {
      if (event.candidate) {
        onCandidate(event.candidate);
      } else {
        console.log("No more ICE candidates");
      }
    };

    // 远端媒体流事件：当远端流到达时触发
    this.peerconnection.ontrack = onTrack;

    // 一些日志事件
    // 连接状态变化事件
    this.peerconnection.oniceconnectionstatechange = () => {
      console.log(
        "ICE Connection State Changed: ",
        this.peerconnection?.iceConnectionState
      );
    };

    // 信令状态变化事件
    this.peerconnection.onsignalingstatechange = () => {
      console.log(
        "Signaling State Changed: ",
        this.peerconnection?.signalingState
      );
    };

    // 连接状态变化事件
    this.peerconnection.onconnectionstatechange = () => {
      console.log(
        "Connection State Changed: ",
        this.peerconnection?.connectionState
      );
    };

    // 连接建立事件
    this.peerconnection.onnegotiationneeded = () => {
      console.log("Negotiation Needed");
    };
  }

  // 创建本地 offer，并设置为本地描述
  async createAndSetLocalOffer(
    onSDP: (sdp: RTCSessionDescriptionInit) => void
  ) {
    if (!this.peerconnection) {
      return console.error("PeerConnection is not initialized");
    }
    try {
      const offer = await this.peerconnection.createOffer();
      await this.peerconnection.setLocalDescription(offer);
      onSDP(offer);
      return offer;
    } catch (error) {
      console.error("Error creating and setting local offer:", error);
    }
  }

  // 创建本地 answer，并设置为本地描述
  async createAndSetLocalAnswer(
    onSDP: (sdp: RTCSessionDescriptionInit) => void
  ) {
    if (!this.peerconnection) {
      return console.error("PeerConnection is not initialized");
    }
    try {
      const answer = await this.peerconnection.createAnswer();
      await this.peerconnection.setLocalDescription(answer);
      onSDP(answer);
      return answer;
    } catch (error) {
      console.error("Error creating and setting local answer:", error);
    }
  }

  // 设置远端描述（sdp）
  async setRemoteDescription(sdp: RTCSessionDescriptionInit) {
    if (!this.peerconnection) {
      return console.error("PeerConnection is not initialized");
    }
    try {
      await this.peerconnection.setRemoteDescription(
        new RTCSessionDescription(sdp)
      );
    } catch (error) {
      console.error("Error setting remote description:", error);
    }
  }

  // 添加远端的 ICE 候选
  async setRemoteCandidate(candidate: RTCIceCandidateInit) {
    if (!this.peerconnection) {
      return console.error("PeerConnection is not initialized");
    }
    try {
      await this.peerconnection.addIceCandidate(candidate);
    } catch (error) {
      console.error("Error adding remote ICE candidate:", error);
    }
  }

  // 将本地流的轨道添加到 peerconnection 中
  addTrack(localStream: MediaStream) {
    if (!this.peerconnection) {
      return console.error("PeerConnection is not initialized");
    }
    try {
      localStream.getTracks().forEach((track) => {
        // 防止该函数被同一个流多次调用，导致添加重复轨道
        const isExistTrack = this.peerconnection
          ?.getSenders()
          .find((sender) => sender.track === track);
        if (!isExistTrack) {
          this.peerconnection?.addTrack(track, localStream);
        }
        console.log(this.peerconnection?.getSenders());
      });
    } catch (error) {
      console.error("Error adding track to peerconnection:", error);
    }
  }

  // 暂停/恢复流的传输与生产
  // (enabled 是“阻止”流，stop() 是关闭流，从而“停止”流，如果使用 stop 需要重新调用getUserMedia 创建)
  toggleTrack(localStream: MediaStream, enabled: boolean) {
    if (!this.peerconnection) {
      return console.error("PeerConnection is not initialized");
    }
    // 停止所有轨道流的传输
    this.peerconnection.getSenders().forEach((sender) => {
      sender.track!.enabled = enabled;
    });
    localStream.getTracks().forEach((track) => {
      track.enabled = enabled;
    });
  }

  // 暂停/恢复视频流的传输与生产
  //（senders 是控制RTC连接上的传输流的）
  toggleVideoTrack(localStream: MediaStream, enabled: boolean) {
    if (!this.peerconnection) {
      return console.error("PeerConnection is not initialized");
    }
    this.peerconnection.getSenders().forEach((sender) => {
      if (sender.track!.kind === "video") {
        sender.track!.enabled = enabled;
      }
    });
    localStream.getVideoTracks().forEach((track) => {
      track.enabled = enabled;
    });
  }

  // 释放连接，清理资源
  close() {
    if (!this.peerconnection) {
      return console.error("PeerConnection is not initialized");
    }
    // 停止所有轨道的传输
    this.peerconnection.getSenders().forEach((sender) => {
      sender.track?.stop();
    });
    // 关闭 RTC 连接
    this.peerconnection.close();
    this.peerconnection = null;
    console.log("Peer connection closed");
  }

  // 一些工具方法
  // 将流注入到本地视频标签中
  setStreamToVideoElm(videoElm: HTMLVideoElement, stream: MediaStream) {
    if (videoElm) {
      // 如果有旧的流，先停止它
      const oldStream = videoElm.srcObject as MediaStream | null;
      if (oldStream) {
        oldStream!.getTracks().forEach((track: MediaStreamTrack) => {
          track.stop();
        });
        videoElm.srcObject = null;
      }
      videoElm.srcObject = stream;
    }
  }

  // 使用新的视频流替换旧的视频流
  changeSendersTrack(newLocalStream: MediaStream) {
    newLocalStream.getVideoTracks().forEach((track) => {
      if (this.peerconnection) {
        const sender = this.peerconnection
          .getSenders()
          .find((sender) => sender.track?.kind === "video");
        if (sender) {
          sender.replaceTrack(track);
        }
      }
    });
  }
}

export default WebrtcConnection;
